package com.zzx.servlet;

import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * @Author: Spider Man
 * @Description: 方法和请求的关系映射
 * @Date Created in 2020-09-10 17:29
 * @Modified By:
 */
public class HandlerMapping {
    /**
     * 用来存储uri和需要操作的对象MVC映射信息
     */
    private static Map<String,MVCMapping> data = new HashMap<>();

    /**
     * 通过请求的uri得到对应的对象
     * @param uri 请求的uri
     * @return uri对应的类对象的信息
     */
    public static MVCMapping getMVCMappingInfo(String uri){
        return data.get(uri);
    }

    /**
     * 此方法用于通过输入流加载读取的类中信息并封装到map中
     * @param inputStream 输入流
     */
    public static void load(InputStream inputStream){
        Properties properties = new Properties();
        try {
            properties.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //获取properties中的所有键值对的值信息
        Collection<Object> values = properties.values();
        for (Object value : values) {
            try {
                // 1.加载键值对中的值信息包含的类对象
                Class classFromProperties = Class.forName((String) value);
                // 2.通过类对象来获取构造方法
                Constructor constructor = classFromProperties.getConstructor();
                // 3.通过构造方法创建该类对应的对象
                Object o = constructor.newInstance();
                // 4.这里再用类第一步获取的类对象来获取该类中的所有
                Method[] methods = classFromProperties.getMethods();
                // 5.对方法的注解进行判断该方法所属的类型（要返回text还是重定向）
                for (Method method : methods) {
                    // 5.1获取方法的注解
                    Annotation[] annotations = method.getAnnotations();
                    // 5.2判断注解的所属类型
                    for (Annotation annotation : annotations) {
                        if (annotation instanceof ResponseText){
                            MVCMapping mvcMapping = new MVCMapping(o,method,ResponseType.TEXT);
                            MVCMapping put = data.put(((ResponseText) annotation).value(), mvcMapping);
                            if (put != null){
                                throw new Exception("请求地址重复"+((ResponseText) annotation).value());
                            }
                        }else if (annotation instanceof ResponseView){
                            MVCMapping mvcMapping = new MVCMapping(o,method, ResponseType.VIEW);
                            MVCMapping put = data.put(((ResponseView) annotation).value(), mvcMapping);
                            if (put != null){
                                throw new Exception("请求地址重复" + ((ResponseView) annotation).value());
                            }
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 静态内部类，封装映射对象及其方法和注解信息
     */
    public static class MVCMapping{
        /**
         * 映射对象
         */
        private Object object;

        /**
         * 映射对象方法
         */
        private Method method;

        /**
         * 映射对象注解的类型
         */
        private ResponseType responseType;

        public MVCMapping() {
        }

        public MVCMapping(Object object, Method method, ResponseType responseType) {
            this.object = object;
            this.method = method;
            this.responseType = responseType;
        }

        public Object getObject() {
            return object;
        }

        public void setObject(Object object) {
            this.object = object;
        }

        public Method getMethod() {
            return method;
        }

        public void setMethod(Method method) {
            this.method = method;
        }

        public ResponseType getResponseType() {
            return responseType;
        }

        public void setResponseType(ResponseType responseType) {
            this.responseType = responseType;
        }
    }
}
